/*
 * Copyright 2025 arisgo@163.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.arisgo.cloud.common.utils;

import com.google.common.hash.Hashing;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author Arisgo
 * @since 2024/3/8
 */
public class CipherUtil {
    // TODO 写于配置文件中
    private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVnyRxcHDg1Ifbu11SBT9erBP3o+q49kzf3G00NuMt/zswu/RaXOyStt4F75PmDJEm3Ld8l2aXHF0M6Csm8Uw6E+J/BWnY3KRJjvO8KJaQ5i9sJ540cqIiOSuULtoyXjmgtzLwChORpPIw92qe1gapLMKzNGOdwQ+yzxG39peU5QIDAQAB";
    private static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANWfJHFwcODUh9u7XVIFP16sE/ej6rj2TN/cbTQ24y3/OzC79Fpc7JK23gXvk+YMkSbct3yXZpccXQzoKybxTDoT4n8FadjcpEmO87wolpDmL2wnnjRyoiI5K5Qu2jJeOaC3MvAKE5Gk8jD3ap7WBqkswrM0Y53BD7LPEbf2l5TlAgMBAAECgYAOWIojfh1ufodYfSGGvRMk4fcopcmWaKAAAUxqJGzRmCGFo9GvRyycq7WG/jBXU4JknY+gSTCatve+wqax46QukNA/f9yNBprAOQwDskCmvqOqe1GtA/8UfB5mPVSScbYM/HaqqH8fl/aiyaTbPfja6HgSNeG3+9x+JpHw2iaQ8QJBAPn7SYPpmY3P2c2ICIiOvKi1wODVRF/PyHN7ej7v4zZi4HE0HC+I1KRB5PdOeuyfdhG6n/bM6IkmdBs3jvWOSZ0CQQDaw8H9oAg3HuFT1z8zAaxcH9zfuWq/Ag7SrOkQZIye+7vBR6eM7AGzrDXrcVnaBavXFa9y/VS3OCWelkjVy1npAkEAqXPutI3AOkIgKVPCPRdMyaxS79WBgNUv0yBrkIg6ZB6IeBRT2uENC79jP0UizI2XkpMIZlsmcfnwEJcLwGbQfQJAPoxOAOgqsSfhIQmgBkNqNoTdsBHhlW9PMalCke9NzX8INcD5BO/NpMOOPx0PpaiNc1e97FDGUgR5rRgnBwm3UQJAFqGUvimqUV6ZwMknSbTtgcXrVxzit21xTCsTupfUG4XXeFAA+ltA/3n6GK43/G8amInFVAAHycHFfUn4LYm1PA==";

    public static String encode(String val, String type) {
        if (!StringUtil.hasLength(type)) {
            throw new RuntimeException("不支持的加密类型");
        }
        return switch (type) {
            case "SHA" -> SHA.encode(val);
            case "RSA" -> RSA.encode(val, PUBLIC_KEY);
            case "AES" -> AES.encode(val, "arisgoCloud-auth");
            case "MD5" -> Md5.encode(val, "arisgo-cloud");
            default -> throw new RuntimeException("不支持的加密类型");
        };
    }

    public static class RSA {

        private static final String RSA_ALG = "RSA";

        /**
         * 随机生成密钥对
         * 密钥长度1024，可加密最大长度 117 (1024/8 -11)
         */
        public static void generatorKey() {
            try {
                // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
                KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALG);
                // 初始化密钥对生成器，密钥大小为
                keyPairGenerator.initialize(1024, new SecureRandom());
                // 生成一个密钥对，保存在keyPair中
                KeyPair keyPair = keyPairGenerator.generateKeyPair();
                // 获取私钥、公钥
                String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
                String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());

                System.out.println("xxx public key: " + publicKey);
                System.out.println("xxx private key: " + privateKey);
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }

        public static String encode(String value, String publicKey) {
            try {
                byte[] decode = Base64.getDecoder().decode(publicKey);
                PublicKey key = KeyFactory.getInstance(RSA_ALG).generatePublic(new X509EncodedKeySpec(decode));
                Cipher cipher = Cipher.getInstance(RSA_ALG);
                cipher.init(Cipher.ENCRYPT_MODE, key);
                byte[] bytes = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8));
                return Base64.getEncoder().encodeToString(bytes);
            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            }
        }

        public static String decode(String value, String privateKey) {
            try {
                byte[] decode = Base64.getDecoder().decode(privateKey);
                PrivateKey key = KeyFactory.getInstance(RSA_ALG).generatePrivate(new PKCS8EncodedKeySpec(decode));
                Cipher cipher = Cipher.getInstance(RSA_ALG);
                cipher.init(Cipher.DECRYPT_MODE, key);
                byte[] val = Base64.getDecoder().decode(value.getBytes(StandardCharsets.UTF_8));
                byte[] bytes = cipher.doFinal(val);
                return new String(bytes);
            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            }
        }

    }

    /**
     * 对称加密
     * TODO
     * 1. 随意的key，转16进制，长度固定为16
     * 2. 加密后的字符长度，长度固定为64位
     */
    public static class AES {

        public static final String AES = "AES";
        public static final String AES_ALG = "AES/CBC/PKCS5Padding";
        /**
         * 初始化向量(根据需求调整向量的值, 也可以将向量添加到入参变量中)
         */
        private static final byte[] SIV = new byte[16];

        /**
         * TODO 随意的key，转16进制，长度固定为16
         */
        public static void generatorKey() {
            try {
                KeyGenerator generator = KeyGenerator.getInstance(AES);
                generator.init(128, new SecureRandom());
                SecretKey secretKey = generator.generateKey();
                String salt = Base64.getEncoder().encodeToString(secretKey.getEncoded());
                System.out.println("salt: " + salt);
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * @param value 加密数据
         * @param key   长度为16
         */
        public static String encode(String value, String key) {
            try {
                Cipher cipher = Cipher.getInstance(AES_ALG);
                // 加密向量
                IvParameterSpec iv = new IvParameterSpec(SIV);
                cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES), iv);
                byte[] b = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8));
                // 采用base64算法进行转码,避免出现中文乱码
                return Base64.getEncoder().encodeToString(b);
            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * @param value 加密数据
         * @param key   秘钥长度为16
         */
        public static String decode(String value, String key) {
            try {
                Cipher cipher = Cipher.getInstance(AES_ALG);
                // 加密向量
                IvParameterSpec iv = new IvParameterSpec(SIV);
                cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(), AES), iv);
                // 采用base64算法进行转码,避免出现中文乱码
                byte[] encryptBytes = Base64.getDecoder().decode(value);
                byte[] decryptBytes = cipher.doFinal(encryptBytes);
                return new String(decryptBytes);
            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            }
        }

    }

    /**
     * 不可逆加密
     */
    public static class SHA {
        /**
         * sha256e加密
         */
        public static String encode(String value) {
            return Hashing.sha256().hashBytes(value.getBytes(StandardCharsets.UTF_8)).toString();
        }
    }

    public static class Md5 {

        private static final char[] hexDigits = "0123456789abcdef".toCharArray();

        /**
         * 转为16进制
         * TODO 缺少16进制转byte[]
         */
        public static String convertHex(byte[] bytes) {
            StringBuilder sb = new StringBuilder(2 * bytes.length);
            for (byte b : bytes) {
                sb.append(hexDigits[(b >> 4) & 0xf]).append(hexDigits[b & 0xf]);
            }
            return sb.toString();
        }

        /**
         * TODO 缺少加盐配置 salt
         */
        public static String encode(String value, String alg) {
            try {
                MessageDigest instance = MessageDigest.getInstance(alg);
                instance.update(value.getBytes());
                return convertHex(instance.digest());
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args) {
        String password = AES.encode("adminSecret", "arisgoSaltSecret");
        System.out.println(password);

        String encode = SHA.encode("123456");
        System.out.println(encode);
    }

}
